﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Face_Recognition
{
    public static class ColorFilters
    {
        private static int[] RGBToYCbCr(int R, int G, int B)
        {
            int Y = (int)(0.299 * R + 0.587 * G + 0.114 * B + 16);
            int Cb = (int)(0.15 * R - 0.30 * G + 0.45 * B + 128);
            int Cr = (int)(0.45 * R - 0.35 * G - 0.07 * B + 128);

            return new int[3] { Y, Cb, Cr };

        }
        private static double[] RGBToIRgBy(int R, int G, int B)
        {
            double I = (LogOpponent(R) + LogOpponent(G) + LogOpponent(B)) / 3;
            double Rg = LogOpponent(R) - LogOpponent(G);
            double By = LogOpponent(B) - (LogOpponent(G) + LogOpponent(B)) / 2;
            return new double[3] { I, Rg, By };
        }

        private static double[] RgByToHueSaturation(double Rg, double By)
        {
            double hue = Math.Pow(Math.Atan2(Rg, By), 2);
            double saturation = Math.Sqrt(Math.Pow(Rg, 2) + Math.Pow(By, 2));

            return new double[2] { hue, saturation };


        }

        private static double LogOpponent(int x)
        {
            return 105 * Math.Log10(x + 1);
        }

        public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
        {
            int max = Math.Max(color.R, Math.Max(color.G, color.B));
            int min = Math.Min(color.R, Math.Min(color.G, color.B));

            hue = color.GetHue();
            saturation = (max == 0) ? 0 : 1d - (1d * min / max);
            value = max / 255d;
        }

        public static List<bool[,]> GetColorsMask(Bitmap bitmap)
        {
            bool[,] mask = new bool[bitmap.Height, bitmap.Width];
            int[] YCbRb = new int[3];
            System.Drawing.Color color;
            for (int w = 0; w < bitmap.Width; w++)
            {
                for (int h = 0; h < bitmap.Height; h++)
                {
                    color = Color.FromArgb(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);
                    YCbRb = RGBToYCbCr(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);

                    //Normalization
                    float r = (color.R + color.G + color.B) > 0 ? (float)((color.R * 3 * 255) / (color.R + color.G + color.B)) : 0;
                    float g = (color.R + color.G + color.B) > 0 ? (float)((color.G * 3 * 255) / (color.R + color.G + color.B)) : 0;
                    float b = (color.R + color.G + color.B) > 0 ? (float)((color.B * 3 * 255) / (color.R + color.G + color.B)) : 0;

                    r = color.R;
                    g = color.G;
                    b = color.B;
                    if (YCbRb[2] > 150 && YCbRb[2] < 165 && YCbRb[1] > 145 && YCbRb[1] < 190 &&
                        (color.GetHue() < 36 || color.GetHue() > 10 ) || (r > 95 && g > 40 && b > 20 && r > b && r < 250
                            && r > g && Math.Abs(r - g) > 15 &&
                            (Math.Max(r, (Math.Max(g, b))) - Math.Min(r, (Math.Min(g, b))) > 15)))
                      
                    {
                        mask[h, w] = true;
                
                        //bitmap.SetPixel(w, h, Color.White);
                    }
                    else
                    {
                        mask[h, w] = false;
                        //bitmap.SetPixel(w, h, Color.Black);
                    }
                }
            }

            List<bool[,]> masks = new List<bool[,]>();

            if(Settings.TextureCheck)
                masks.Add(TextureFilters.TextureCheck(bitmap, mask, 7));
            else
                masks.Add(mask);

            if(Settings.SobelBoundaries)
                masks.Add(TextureFilters.Sobel(bitmap));
            
            if (Settings.ColorSobelBoundaries)
                masks.Add(TextureFilters.ColorSobel(bitmap));

            if (Settings.ShowSkinMap)
            {
                for (int w = 0; w < bitmap.Width; w++)
                {
                    for (int h = 0; h < bitmap.Height; h++)
                    {
                        if (masks[0][h, w] == true)
                             bitmap.SetPixel(w, h, Color.White);
                        else
                             bitmap.SetPixel(w, h, Color.Black);
                    }
                }
            }


            if (Settings.ShowThinnedEdges)
            {
                for (int w = 0; w < bitmap.Width; w++)
                {
                    for (int h = 0; h < bitmap.Height; h++)
                    {
                        if (masks[1][h, w] == true)
                        {
                            bitmap.SetPixel(w, h, Color.Orange);
                        }
                    }
                }
            }

            return masks;
        }

        public static bool CheckRectangleColors(Bitmap bitmap, Rectangle rectangle)
        {
            int[] YCbRb = new int[3];
            System.Drawing.Color color;
            int skinCount = 0;
            for (int w = rectangle.X; w < rectangle.X + rectangle.Width; w++)
            {
                for (int h = rectangle.Y; h < rectangle.Y + rectangle.Height; h++)
                {
                    color = Color.FromArgb(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);
                    YCbRb = RGBToYCbCr(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);

                    //Normalization
                    float r = (color.R + color.G + color.B) > 0 ? (float)((color.R * 3 * 255) / (color.R + color.G + color.B)) : 0;
                    float g = (color.R + color.G + color.B) > 0 ? (float)((color.G * 3 * 255) / (color.R + color.G + color.B)) : 0;
                    float b = (color.R + color.G + color.B) > 0 ? (float)((color.B * 3 * 255) / (color.R + color.G + color.B)) : 0;

                    r = color.R;
                    g = color.G;
                    b = color.B;
                    if (YCbRb[2] > 150 && YCbRb[2] < 165 && YCbRb[1] > 145 && YCbRb[1] < 190 &&
                        (color.GetHue() < 36 || color.GetHue() > 10) || (r > 95 && g > 40 && b > 20 && r > b && r < 250
                            && r > g && Math.Abs(r - g) > 15 &&
                            (Math.Max(r, (Math.Max(g, b))) - Math.Min(r, (Math.Min(g, b))) > 15)))
                    {
                        skinCount++;
                    }
                    else
                    {
                        //bitmap.SetPixel(w, h, Color.Black);
                    }
                }
            }
            if (skinCount > (rectangle.Width * rectangle.Height / 2))
                return true;
            else
                return false;
        }

        private static bool[,] GetYCbCrMask(Bitmap bitmap)
        {
            bool[,] mask = new bool[bitmap.Height,bitmap.Width];
            int[] YCbRb = new int[3];
            for (int w = 0; w < bitmap.Width; w++)
            {
                for (int h = 0; h < bitmap.Height; h++)
                {
                    YCbRb = RGBToYCbCr(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);
                    if (YCbRb[2] > 130 && YCbRb[2] < 170 && YCbRb[1] > 75 && YCbRb[1] < 130)
                        mask[h, w] = true;
                    else
                        mask[h, w] = false;
                }
            }

            return mask;
        }

        private static bool[,] GetHSVMask(Bitmap bitmap)
        {
            bool[,] mask = new bool[bitmap.Height, bitmap.Width];
            System.Drawing.Color color;
            for (int w = 0; w < bitmap.Width; w++)
            {
                for (int h = 0; h < bitmap.Height; h++)
                {
                    color = Color.FromArgb(bitmap.GetPixel(w, h).R, bitmap.GetPixel(w, h).G, bitmap.GetPixel(w, h).B);
                    if ((color.GetHue() < 40 && color.GetHue() > 0 || color.GetHue() < 370 && color.GetHue() > 325) && color.GetSaturation() > 0.2)
                        mask[h, w] = true;
                    else
                        mask[h, w] = false;
                }
            }

            return mask ;
        }

        private static bool[,] GetRGBMask(Bitmap bitmap)
        {
            bool[,] mask = new bool[bitmap.Height, bitmap.Width];
            for (int w = 0; w < bitmap.Width; w++)
            {
                for (int h = 0; h < bitmap.Height; h++)
                {
                    if (bitmap.GetPixel(w, h).R > 90 && bitmap.GetPixel(w, h).G > 30 && bitmap.GetPixel(w, h).B > 20 && bitmap.GetPixel(w, h).R > bitmap.GetPixel(w, h).B
                        && bitmap.GetPixel(w, h).R > bitmap.GetPixel(w, h).G && Math.Abs(bitmap.GetPixel(w, h).R - bitmap.GetPixel(w, h).G) > 10)
                        mask[h, w] = true;
                    else
                        mask[h, w] = false;
                }
            }

            return mask;
        }
    }
}
